package com.linkgie.galaxyframework.security;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

import com.linkgie.galaxyframework.organization.Organization;

public interface SecurityContext extends AuthenticationContext {

	/**
	 * 是否为匿名访问；
	 * 
	 * @return
	 */
	boolean isAnonymous();

	/**
	 * 是否已认证；
	 * 
	 * @return
	 */
	boolean isAuthenticated();

	/**
	 * 登录Id；
	 * 
	 * @return
	 */
	long getLoginId();

	/**
	 * 登录凭据名称；
	 * <p>
	 * 返回值与登录方式有关， 例如，以用户名密码登录时，返回的是用户名；
	 * 
	 * @return
	 */
	String getCredentialName();

	/**
	 * 当前认证中登录的账号的主体信息；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 */
	AccountPrincipal getAccountPrincipal() throws ApplicationSecurityException;

	/**
	 * 当前认证中登录的机构的主体信息；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 */
	OrganizationPrincipal getOrganizationPrincipal() throws ApplicationSecurityException;

	/**
	 * 当前认证中登录的应用；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 * @throws ApplicationSecurityException
	 */
	OpenApplication getApplication() throws ApplicationSecurityException;

	/**
	 * 当前认证中登录的应用用户详情；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 * @throws ApplicationSecurityException
	 */
	OpenUserDetails getOpenUserDetails() throws ApplicationSecurityException;

	/**
	 * 更新上下文的用户资料；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * <p>
	 * 注：此方法仅更新上下文缓存的用户资料，不会更新数据库中的用户资料；
	 * 
	 * @param userProfile 用户资料；
	 * @return
	 * @throws ApplicationSecurityException
	 */
	void setUserProfile(UserProfile userProfile) throws ApplicationSecurityException;

	/**
	 * 已授权的机构列表；
	 * <p>
	 * 当前账号可切换登录到其中的机构；
	 * <p>
	 * 如果当前上下文未认证，则引发异常 {@link ApplicationSecurityException}；
	 * 
	 * @return
	 */
	Set<Organization> getAuthorizedOrganizations() throws ApplicationSecurityException;

	/**
	 * 当前认证中登录的账号的主体信息；
	 * <p>
	 * 如果当前上下文未认证，则返回 null；
	 * 
	 * @return
	 */
	AccountPrincipal tryGetAccountPrincipal();

	/**
	 * 当前认证中登录的机构的主体信息；
	 * <p>
	 * 如果当前上下文未认证，则返回 null；
	 * 
	 * @return
	 */
	OrganizationPrincipal tryGetOrganizationPrincipal();

	/**
	 * 当前认证中登录的应用；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则返回 null；
	 * 
	 * @return
	 */
	OpenApplication tryGetApplication();

	/**
	 * 当前认证中登录的应用用户详情；
	 * <p>
	 * 如果当前认证账号没有应用用户身份，或者不是以应用用户身份登录，则返回 null ；
	 * <p>
	 * 如果当前上下文未认证，则返回 null；
	 * 
	 * @return
	 */
	OpenUserDetails tryGetOpenUserDetails();

	/**
	 * 已授权的机构列表；
	 * <p>
	 * 当前账号可切换登录到其中的机构；
	 * <p>
	 * 如果当前上下文未认证，则返回 {@link Collections#emptySet()}；
	 * 
	 * @return
	 */
	Set<Organization> tryGetAuthorizedOrganizations();

	/**
	 * 创建一个以当前上下文执行的任务；
	 * <p>
	 * 在任务的执行过程中，任务线程会切换到当前上下文，以当前上下文的登录身份执行;
	 * <br>
	 * 并且在执行完成并返回结果之后，将恢复线程上下文，避免任务线程被复用的时候，当前的登录身份被错误地泄露到其它的任务中；
	 *
	 * @param <T>      返回值类型；
	 * @param callable 要执行的任务；
	 * @return
	 */
	<T> FutureTask<T> createTask(Callable<T> callable);

	/**
	 * 创建一个以当前上下文执行的任务；
	 * <p>
	 * 在任务的执行过程中，任务线程会切换到当前上下文，以当前上下文的登录身份执行;
	 * <br>
	 * 并且在执行完成并返回结果之后，将恢复线程上下文，避免任务线程被复用的时候，当前的登录身份被错误地泄露到其它的任务中；
	 *
	 * @param <T>      返回值类型；
	 * @param runnable 要执行的任务；
	 * @return
	 */
	default FutureTask<Void> createTask(Runnable runnable) {
		return createTask(runnable, null);
	}

	/**
	 * 创建一个以当前上下文执行的任务；
	 * <p>
	 * 在任务的执行过程中，任务线程会切换到当前上下文，以当前上下文的登录身份执行;
	 * <br>
	 * 并且在执行完成并返回结果之后，将恢复线程上下文，避免任务线程被复用的时候，当前的登录身份被错误地泄露到其它的任务中；
	 *
	 * @param <T>      返回值类型；
	 * @param runnable 要执行的任务；
	 * @param result   执行成功后返回的结果；
	 * @return
	 */
	<T> FutureTask<T> createTask(Runnable runnable, T result);

}
